Skip to content

fix(@angular/ssr): normalize patched host headers#33126

Closed
Hexix23 wants to merge 1 commit intoangular:21.1.xfrom
Hexix23:fix-ssr-normalize-patched-host-headers
Closed

fix(@angular/ssr): normalize patched host headers#33126
Hexix23 wants to merge 1 commit intoangular:21.1.xfrom
Hexix23:fix-ssr-normalize-patched-host-headers

Conversation

@Hexix23
Copy link
Copy Markdown

@Hexix23 Hexix23 commented May 5, 2026

This fix addresses an SSRF / host-confusion hardening issue in the @angular/ssr
cloneRequestAndPatchHeaders() code path on the 21.1.x release branch. The same
code path was present in earlier 21.2.x builds before it was replaced by the newer
trusted proxy header flow.

The affected code cloneRequestAndPatchHeaders() validated only the first comma-separated token
of Host / X-Forwarded-Host, but returned the original raw header value to
application code through the patched Headers accessors.

This PR follows Google OSS VRP guidance to work with the Angular maintainers via
a public GitHub PR for this issue.

Changes:

  • Normalize cloned Host and X-Forwarded-Host header values to the first
    comma-separated token before application code can read them
  • Preserve existing validation behavior for the normalized token
  • Add regression tests for get(), entries(), values(), forEach(), and
    for...of reads

This aligns the values returned to application code with the value Angular already
uses for validation and internal URL construction.

PR Checklist

Please check if your PR fulfills the following requirements:

  • The commit message follows our guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other... Please describe:

What is the current behavior?

Issue Number: N/A

cloneRequestAndPatchHeaders() patches Headers.get(), Headers.entries(),
Headers.values(), Headers.forEach(), and [Symbol.iterator] so host headers
are validated when application code reads them. The validation path uses the first
comma-separated header token. However, the patched accessors return the raw header
string.

For example, with allowedHosts = new Set(['example.com']),
X-Forwarded-Host: example.com,@127.0.0.1:8765 validates as example.com, but
application code reading request.headers.get('x-forwarded-host') receives the
raw value example.com,@127.0.0.1:8765.

What is the new behavior?

The cloned request normalizes Host and X-Forwarded-Host to the same first
comma-separated token that Angular validates. Application code therefore receives
example.com in the example above, rather than the unvalidated suffix.

Other headers are unchanged; e.g. Accept: text/html, application/json still
returns the full value.

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Validated locally with:

bazelisk test //packages/angular/ssr/test:test

Bazel reported the target as flaky because the first attempt hit unrelated existing
app_spec.ts failures, then retried and completed with the test target passing.

Return the same first host-header token that is validated so application code cannot receive unvalidated forwarded-host suffixes.
@Hexix23 Hexix23 force-pushed the fix-ssr-normalize-patched-host-headers branch from 12a0f4b to 1c411bd Compare May 5, 2026 08:25
@Hexix23 Hexix23 changed the base branch from 21.2.x to 21.1.x May 5, 2026 08:25
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request enhances security in Angular SSR by proactively normalizing host headers during the request cloning process. It ensures that headers like 'host' and 'x-forwarded-host' are set to their first validated token before the request is processed. New unit tests have been added to verify this behavior during direct header access and iteration. A review comment suggests also patching the set() and append() methods of the headers object to prevent subsequent modifications from bypassing the normalization logic.

I am having trouble creating individual review comments. Click here to see my feedback.

packages/angular/ssr/src/utils/validation.ts (111-117)

security-medium medium

The normalization of host headers is performed only once during the initialization of the cloned request. If application code or middleware subsequently modifies these headers using headers.set() or headers.append(), the normalization will be lost, although the patched get() method will still trigger validation on the first token of the new value. While this addresses the primary SSRF risk, consider if set() and append() should also be patched to maintain normalization throughout the request lifecycle for these specific headers.

@Hexix23
Copy link
Copy Markdown
Author

Hexix23 commented May 5, 2026

Closing this PR. The vulnerable code path targeted here no longer exists in the current 21.2.x branch, where it has been replaced by the trusted proxy header flow. This PR was effectively a 21.1.x backport/hardening change, and I am withdrawing it rather than pursuing that backport.

@Hexix23 Hexix23 closed this May 5, 2026
@Hexix23 Hexix23 deleted the fix-ssr-normalize-patched-host-headers branch May 5, 2026 08:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant